<?php

namespace App\Services\YunXinCloud;


use App\Exception\MessageException;
use App\Utils\LoggerUtil;
use Throwable;
use function Hyperf\Config\config;

class WyyClient
{
    private mixed $AppKey;
    private mixed $AppSecret;
    private string $Nonce;
    private string $CurTime;
    private string $CheckSum;
    private mixed $baseUrl;
    public mixed $from;
    protected mixed $env;


    public function __construct()
    {
        $this->baseUrl = config('yunxin.base_url');
        $this->AppKey = config('yunxin.appkey');
        $this->AppSecret = config('yunxin.appsecret');
        $this->from = config('yunxin.from');
        $this->env = config('yunxin.env');
        $this->Nonce = uniqid();
        $this->CurTime = (string)time();
        $this->initCheckSum();
    }


    /**
     * 音视频2.0 Token鉴权
     * @param  $uid //用户id
     * @param  $call_id //绑定的房间名称
     * @param int $expireAt //Token 的过期时间，过期后，该用户将无法通过此 Token 加入房间
     * @return mixed|string
     */
    public function getTokenYunXin($uid, $call_id, int $expireAt = 600)
    {
        $url = '/user/getToken.action';
        $data = array(
            'uid' => $uid,
            'channelName' => $call_id,
            'expireAt' => $expireAt
        );
        $result = $this->postDataCurl($url, $data);
        if ($result["code"] == 200) {
            return $result["token"];
        } else {
            return "";
        }

    }


    /**
     * 生成CheckSum
     */
    private function initCheckSum()
    {
        $this->CheckSum = sha1("{$this->AppSecret}{$this->Nonce}{$this->CurTime}");
    }


    /**
     * 验证 CheckSum
     * @param $MD5
     * @param $CurTime
     * @param $CheckSum
     * @return bool
     */
    public function verifyCheckSum($MD5, $CurTime, $CheckSum)
    {
        $join_string = $this->AppSecret . $MD5 . $CurTime;
        $CheckSumTrue = sha1($join_string);
        return ($CheckSum === $CheckSumTrue);
    }


    /**
     * json转数组
     * @param $json_str
     * @return array
     */
    public function json2array($json_str)
    {
        if (is_array($json_str) || is_object($json_str) || is_null(json_decode($json_str))) {
            $json_str = $json_str;
        } else {
            $json_str = strval($json_str);
            $json_str = json_decode($json_str, true);
        }
        $json_arr = array();
        foreach ($json_str as $k => $w) {
            if (is_object($w)) {
                $json_arr[$k] = $this->json2array($w); //判断类型是不是object
            } else if (is_array($w)) {
                $json_arr[$k] = $this->json2array($w);
            } else {
                $json_arr[$k] = $w;
            }
        }
        return $json_arr;
    }

    /**
     * 发送curl请求
     * @param string $url
     * @param array $postData
     * @param int $timeout
     * @return array
     */
    public function postDataCurl(string $url, array $postData, int $timeout = 5000)
    {
        $httpHeader = array(
            'AppKey:' . $this->AppKey,
            'Nonce:' . $this->Nonce,
            'CurTime:' . $this->CurTime,
            'CheckSum:' . $this->CheckSum,
            'Content-Type:application/x-www-form-urlencoded;charset=utf-8',
        );

        $postDataArray = array();
        foreach ($postData as $key => $value) {
            $postDataArray[] = $key . '=' . urlencode($value);
        }
        $postData = join('&', $postDataArray);
        //die(urldecode($postData));

        $url = $this->baseUrl . $url;

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $httpHeader);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //处理http证书问题
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

        $response = curl_exec($ch);

        LoggerUtil::write('wyy_postDataCurl', $response);

        //die($response);
        if (false === $response) {
            die(json_encode(curl_getinfo($ch)));
        }
        curl_close($ch);
        return $this->json2array($response);
    }

    /**
     * 使用FSOCKOPEN方式发送post请求
     * @param  $url [请求地址]
     * @param  $data [array格式数据]
     * @return $请求返回结果(array)
     */
    public function postDataFsockopen($url, $data)
    {
        $postdata = '';
        foreach ($data as $key => $value) {
            $postdata .= ($key . '=' . urlencode($value) . '&');
        }
        $URL_Info = parse_url($url);
        if (!isset($URL_Info["port"])) {
            $URL_Info["port"] = 80;
        }
        $request = '';
        $request .= "POST " . $URL_Info["path"] . " HTTP/1.1\r\n";
        $request .= "Host:" . $URL_Info["host"] . "\r\n";
        $request .= "Content-type: application/x-www-form-urlencoded;charset=utf-8\r\n";
        $request .= "Content-length: " . strlen($postdata) . "\r\n";
        $request .= "Connection: close\r\n";
        $request .= "AppKey: " . $this->AppKey . "\r\n";
        $request .= "Nonce: " . $this->Nonce . "\r\n";
        $request .= "CurTime: " . $this->CurTime . "\r\n";
        $request .= "CheckSum: " . $this->CheckSum . "\r\n";
        $request .= "\r\n";
        $request .= $postdata . "\r\n";

        print_r($request);
        $fp = fsockopen($URL_Info["host"], $URL_Info["port"]);
        fputs($fp, $request);
        $result = '';
        while (!feof($fp)) {
            $result .= fgets($fp, 128);
        }
        fclose($fp);

        $str_s = strpos($result, '{');
        $str_e = strrpos($result, '}');
        $str = substr($result, $str_s, $str_e - $str_s + 1);
        print_r($result);
        return $this->json2array($str);
    }


    /**
     * 生成token
     * @param $uid
     * @return string
     */
    public function genToken($uid)
    {
        $curTime = getMillisecond();
        $ttl = 3600 * 24 * 7;
        $AppKey = $this->AppKey;
        $AppSecret = $this->AppSecret;
        $str = "{$AppKey}{$uid}{$curTime}{$ttl}{$AppSecret}";
        $signature = sha1($str);
        $json = compact("signature", "curTime", "ttl");
        $json = json_encode($json);
        return base64_encode($json);
    }

    /**
     * 创建网易云信IM账号
     * @param $uid [会员id]
     * @return false|array
     */
    public function createUser($uid)
    {
        $url = '/user/create.action';
        $data = array(
            'accid' => $uid,
        );
        $result = $this->postDataCurl($url, $data);
        if ($result["code"] !== 200) {
            return false;
        }
        return $result["info"]["token"];
    }

    /**
     * 重置网易云信IM token
     * @param $uid [会员id]
     * @return false|array
     */
    public function refreshUser($uid)
    {
        $url = '/user/refreshToken.action';
        $data = array(
            'accid' => $uid,
        );

        $result = $this->postDataCurl($url, $data);

        if ($result["code"] !== 200) {
            return false;
        }

        return $result["info"]["token"];
    }

    /**
     * 更新用户名片
     * @param $uid [uid]
     * @param $nickname [用户昵称]
     * @param $headImage [用户头像]
     * @return array
     */
    public function updateUserInfo($uid, $nickname, $headImage)
    {
        $url = '/user/updateUinfo.action';
        $data = array(
            'accid' => $uid,
            'name' => $nickname,
            'icon' => $headImage,
        );

        return $this->postDataCurl($url, $data);
    }


    /**
     * Note - 发送自定义点对点普通消息
     * DateTime 2024/7/31 15:54
     * User Admin
     * @param $fromUid
     * @param $toUid
     * @param $message
     * @return bool
     */
    public function sendCustomMsg($fromUid, $toUid, $message)
    {
        try {
            $url = "/msg/sendMsg.action";
            $args = [
                "from" => (string)$fromUid,
                "ope" => 0,
                "to" => (string)$toUid,
                "type" => 100,
                "body" => json_encode(["custom_p2p_msg" => 1]),
                "ext" => $message,
                "env" => $this->env,
            ];
            LoggerUtil::write("custom_msg", ['uid' => $fromUid, 'args' => $args]);
            $result = $this->postDataCurl($url, $args);
            LoggerUtil::write("custom_msg", ['uid' => $fromUid, 'result' => $result]);
            if ($result["code"] !== 200 || !isset($result["data"]["msgid"])) {
                throw new \Exception(json_encode($result));
            }

            return true;
        } catch (\Throwable $e) {
            LoggerUtil::write("custom_msg", [
                "uid" => $fromUid,
                "message" => $e->getMessage(),
                "file" => $e->getFile(),
                "line" => $e->getLine(),
            ]);
            return false;
        }
    }


    /**
     * 发送单个系统消息
     * @param $fromUid
     * @param $toUid
     * @param $message
     * @return mixed|string
     */
    public function sendAttachMsg($fromUid, $toUid, $message)
    {
        try {
            $url = "/msg/sendAttachMsg.action";
            $args = [
                "from" => (string)$fromUid,
                "msgtype" => 0,
                "to" => (string)$toUid,
                "attach" => $message,
                "env" => $this->env,
            ];
            $result = $this->postDataCurl($url, $args);
            LoggerUtil::write("attach_msg_queue_job", ['uid' => $toUid, 'result' => $result], 'service');
            if ($result["code"] !== 200) {
                return false;
            }

            return true;
        } catch (\Throwable $e) {
            LoggerUtil::write("attach_msg_queue_job", [
                "message" => $e->getMessage(),
                "file" => $e->getFile(),
                "line" => $e->getLine(),
            ], 'service');
            return false;
        }
    }

    /**
     * 发送单个系统消息（视频通话相关im单独发）
     * @param $fromUid
     * @param $toUid
     * @param $message
     * @return mixed|string
     */
    public function sendCallMsg($fromUid, $toUid, $message)
    {
        try {
            $url = "/msg/sendAttachMsg.action";
            $args = [
                "from" => (string)$fromUid,
                "msgtype" => 0,
                "to" => (string)$toUid,
                "attach" => $message,
                "env" => $this->env,
            ];
            LoggerUtil::write("send_call_msg", ['uid' => $toUid, 'args' => $args]);
            $result = $this->postDataCurl($url, $args);
            LoggerUtil::write("send_call_msg", ['uid' => $toUid, 'result' => $result]);
            if ($result["code"] !== 200) {
                throw new \Exception(json_encode($result));
            }

            return true;
        } catch (\Throwable $e) {
            LoggerUtil::write('send_call_msg', [
                $e->getFile(), $e->getLine(), $e->getMessage()
            ]);
            return false;
        }
    }


    /**
     * 批量发送系统消息
     * @param $message
     * @param $toUids
     * @return mixed|string
     */
    public function sendBatchAttachMsg($message, $toUids)
    {
        try {
            if (is_string($toUids)) {
                $toUids = explode(",", $toUids);
            }
            $toUids = json_encode($toUids);

            $url = "/msg/sendBatchAttachMsg.action";
            $args = [
                "fromAccid" => (string)$this->from,
                "toAccids" => $toUids,
                "attach" => is_array($message) ? json_encode($message) : $message,
                "env" => $this->env,
                "option" => json_encode(['route' => false])
            ];
            logInfo("batch_attach_msg_queue", $args);
            $result = $this->postDataCurl($url, $args);
            logInfo("batch_attach_msg_queue", $result);
            if ($result["code"] !== 200) {
                throw new \Exception(json_encode($result));
            }

            return true;
        } catch (Throwable $e) {
            LoggerUtil::write("batch_attach_msg_queue", [
                "message" => $e->getMessage(),
                "file" => $e->getFile(),
                "line" => $e->getLine(),
            ]);
            return false;
        }
    }


    /**
     * 批量发送用户状态消息
     * @param $from_uid
     * @param $toUids
     * @param $message
     * @return mixed|string
     */
    public function sendBatchUserOlineStatusMsg($from_uid, $toUids, $message)
    {
        try {
            $toUids = explode(",", $toUids);
            $toUids = json_encode($toUids);

            $url = "/msg/sendBatchAttachMsg.action";
            $args = [
                "fromAccid" => $from_uid,
                "toAccids" => $toUids,
                "attach" => is_array($message) ? json_encode($message) : $message,
                "env" => $this->env,

            ];
            $result = $this->postDataCurl($url, $args);
            if ($result["code"] !== 200) {
                throw new \Exception(json_encode($result));
            }
            return true;
        } catch (Throwable $e) {
            LoggerUtil::write("user_online_status_queue_job", [
                "message" => $e->getMessage(),
                "file" => $e->getFile(),
                "line" => $e->getLine(),
            ], 'service');
            return false;
        }
    }


    /**
     * 发送广播消息
     * @param $message
     * @return mixed|string
     */
    public function broadcastSend($message)
    {
        try {
            if (is_array($message)) {
                $message = json_encode($message, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
            }
            $url = "/msg/broadcastMsg.action";
            $args = [
                "body" => $message,
            ];

            $result = $this->postDataCurl($url, $args);
            if ($result["code"] !== 200) {
                throw new \Exception(json_encode($result));
            }
            return true;
        } catch (Throwable $e) {
            return false;
        }
    }


    /**
     * 用户登录登出事件记录查询
     * @param $uid
     * @return mixed|string
     */
    public function queryUserEvents($uid)
    {
        try {
            $url = "/user/userOnlineStatus.action";
            $args = [
                "accids" => json_encode([$uid]),
            ];
            $result = $this->postDataCurl($url, $args);
            LoggerUtil::write("query_user_events", ["uid" => $uid, 'result' => $result]);
            if ($result["code"] !== 200) {
                throw new MessageException(json_encode($result), 200);
                // throw new \Exception(json_encode($result));
            }
            if (!isset($result["data"])) {
                throw new MessageException(json_encode($result), 200);
                // throw new \Exception(json_encode($result));
            }
            if (!isset($result["data"]['status'])) {
                throw new MessageException(json_encode($result), 200);
                // throw new \Exception(json_encode($result));
            }
            if (!isset($result["data"]['status'][$uid])) {
                throw new MessageException(json_encode($result), 200);
                // throw new \Exception(json_encode($result));
            }

            return '1';
        } catch (\Throwable $e) {
            LoggerUtil::write("query_user_events", $e->getMessage(), 'error');
            return '0';
        }
    }


}